#include <iostream>

#include <json/json.h>

#include "CnfSvr.h"
#include "CnfSvrCommon.h"
#include "ProtoHelper.h"
#include "CnfSvrProtoHelper.h"
#include "CnfSvrDBHelper.h"


LoggerPtr CnfSvr::_logger(Logger::getLogger("CnfSvr"));

using std::cout;
using std::endl;

int CnfSvr::thread_init_func(void * arg) {
	mysql_thread_init();
	return 0;
}

int CnfSvr::dispatch_request(int cmd_id, json_object * j, string & response) {
	int ret = -1;
	switch (cmd_id) {
		case CMD_GET_ALL_CNF:
			ret = handle_get_all_cnf(j, response);
			break;
		default:
			LOG4CXX_ERROR(_logger, "unknown command, cmd_id:" << cmd_id);
			ret = -100;
	}
	return ret;
}

int CnfSvr::handle_get_all_cnf(json_object * j, string & response) {
	NS_CNF ns;
	list<MDS_CNF> l_mds;
	list<DS_CNF> l_ds;
	MysqlConnPtr cp;
	int ret = _mysql_conn_pool.get(cp);
	if (ret < 0) {
		LOG4CXX_ERROR(_logger, "in get all cnf, could not get mysql conn, ret:" << ret);
		response = build_error_response(CS_ERR_DB_CONN_ERR);
		return -1;
	}
	ret = db_get_all_cnf(cp.get(), ns, l_mds, l_ds);
	if (ret < 0) {
		LOG4CXX_ERROR(_logger, "in get all cnf, db op error, ret:" << ret);
		response = build_error_response(CS_ERR_DB_OP_ERR);
		return -2;
	}
	response = build_response_get_all_cnf(ns, l_mds, l_ds);
	LOG4CXX_INFO(_logger, __FUNCTION__ << ", response:" << response); 
	return 1;
}

int CnfSvr::handle_socket_input_func(int fd, void * arg) {
	CnfSvr * cs = (CnfSvr *)arg;
	json_object * j;
	int cmd_id;
	string request;
	int ret = recv_and_parse_request(fd, cs->_socket_recv_timeout, cs->_max_request_size, j, cmd_id, request);
	if (ret < 0) {
		LOG4CXX_ERROR(_logger, "recv and parse request error, ret:" << ret);
		return -1;
	}
	string response;
	ret = cs->dispatch_request(cmd_id, j, response);
	json_object_put(j);
	if (response.size() < 1) response = build_error_response(CS_ERR_UNKNOWN_ERR); 
	ret = send_cmd(fd, cs->_socket_send_timeout, response.data(), response.size());
	if (ret < 0) {
		LOG4CXX_ERROR(_logger, "reply cmd error, ret:" << ret << ", fd:" << fd << ", request:" << request << \
					", response:" << response);
		return -2;
	}
	return 2;
}

int CnfSvr::init(const char * listen_ip, unsigned short listen_port, int thread_num, const char * log_conf_file, \
		int socket_idle_timeout, int socket_send_timeout, int socket_recv_timeout, int max_request_size, \
		const char * mysql_svr_host, unsigned short mysql_svr_port, const char * mysql_user, \
		const char * mysql_password, const char * mysql_db_name, unsigned int mysql_pool_size) {
	if (NULL == listen_ip || listen_port < 1 || thread_num < 1 || NULL == log_conf_file || NULL == mysql_svr_host || \
		mysql_svr_port < 1 || NULL == mysql_user || NULL == mysql_password || NULL == mysql_db_name || \
		mysql_pool_size < 1) {
			LOG4CXX_ERROR(_logger, "init error, invalid args");
			return -1;
	}
	_listen_ip = listen_ip;
	_listen_port = listen_port;
	_thread_num = thread_num;
	_log_conf_file = log_conf_file;
	_socket_idle_timeout = socket_idle_timeout;
	_mysql_svr_host = mysql_svr_host;
	_mysql_svr_port = mysql_svr_port;
	_mysql_user = mysql_user;
	_mysql_password = mysql_password;
	_mysql_db_name = mysql_db_name;
	_mysql_pool_size = mysql_pool_size;
	_socket_send_timeout = socket_send_timeout;
	_socket_recv_timeout = socket_recv_timeout;
	_max_request_size = max_request_size;
	_sfw.init_logger(log_conf_file);
	int ret = _sfw.init(thread_num, handle_socket_input_func, this, listen_ip,  \
				listen_port, socket_idle_timeout, thread_init_func, this);
	if (ret < 0) {
		LOG4CXX_ERROR(_logger, "init error, server frame work init ret:" << ret);
		return -2;
	}
	ret = _mysql_conn_pool.init(mysql_svr_host, mysql_svr_port, mysql_user, mysql_password, mysql_db_name, mysql_pool_size);
	if (ret < 0) {
		LOG4CXX_ERROR(_logger, "init error, mysql conn pool init ret:" << ret);
		return -3;
	}
	LOG4CXX_INFO(_logger, "init cnf svr ok, listen_ip:" << listen_ip << ", listen_port:" << listen_port << ", thread_num:" << \
			thread_num << ", log_conf_file:" << log_conf_file << ", socket_idle_timeout:" << socket_idle_timeout << \
			", socket_send_timeout:" << socket_send_timeout << ", socket_recv_timeout:" << socket_recv_timeout << \
			", max_request_size:" << max_request_size << ", mysql_svr_host:" << mysql_svr_host << \
			", mysql_svr_port:" << mysql_svr_port << ", mysql_user:" << mysql_user << ", mysql_password:" << \
			mysql_password << ", mysql_db_name:" << mysql_db_name << ", mysql_pool_size:" << mysql_pool_size);
	return 0;
}

int CnfSvr::start() {
	_sfw.start_server();
}
